import random
import re
import string
import webapp2
import hashlib
import logging
from HTMLParser import HTMLParser


def random_string(size=6, chars=string.ascii_letters + string.digits):
    """ Generate random string """
    return ''.join(random.choice(chars) for _ in range(size))


def random_float(start, stop, step):
    """
    Generate random Float
    http://stackoverflow.com/questions/11949179/how-to-get-a-random-float-with-step-in-python
    """
    return random.randint(0, int(round((stop - start) / step))) * step + start


def hashing(plaintext, salt=""):
    """ Returns the hashed and encrypted hexdigest of a plaintext and salt"""
    app = webapp2.get_app()

    # Hashing (sha512)
    plaintext = "%s@%s" % (plaintext, salt)
    phrase_digest = hashlib.sha512(plaintext.encode('UTF-8')).hexdigest()

    # Encryption (PyCrypto)
    # wow... it's so secure :)
    try:
        from Crypto.Cipher import AES
        mode = AES.MODE_CBC

        # We can not generate random initialization vector because is difficult to retrieve them later without knowing
        # a priori the hash to match. We take 16 bytes from the hexdigest to make the vectors different for each hashed
        # plaintext.
        iv = phrase_digest[:16]
        encryptor = AES.new(app.config.get('aes_key'), mode, iv)
        ciphertext = [encryptor.encrypt(chunk) for chunk in chunks(phrase_digest, 16)]
        return ''.join(ciphertext)
    except (ImportError, NameError):
        logging.error("CRYPTO is not running")
        return phrase_digest


def chunks(list, size):
    """ Yield successive sized chunks from list. """

    for i in xrange(0, len(list), size):
        yield list[i:i + size]

EMAIL_REGEXP = "^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$"


def is_email_valid(email):
    if len(email) > 7:
        if re.match(EMAIL_REGEXP, email) != None:
            return 1
    return 0


# Copyright 2008 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Extended and ported to NDB by Bryan Goldstein.
# https://gist.github.com/brysgo/1572547

"""Utility classes and methods for use with simplejson and appengine.

Provides both a specialized simplejson encoder, ModelEncoder, designed to simplify
encoding directly from NDB Models and query results to JSON. A helper function,
encode, is also provided to further simplify usage.

  ModelEncoder: Adds support for NDB Models to simplejson.
  encode(input): Direct method to encode NDB Model objects as JSON.
"""
import datetime
import json
import time
# from google.appengine.api import users
from google.appengine.ext import ndb
from google.appengine.ext.ndb import model, query


class ModelEncoder(json.JSONEncoder):
    """
    Extends JSONEncoder to add support for NDB Models and query results.

    Adds support to simplejson JSONEncoders for NDB Models and query results by
    overriding JSONEncoder's default method.
    """

    def default(self, obj):
        """Tests the input object, obj, to encode as JSON."""
        if hasattr(obj, 'to_dict'):
            obj1 = getattr(obj, 'to_dict')()
            if hasattr(obj, 'key'):
                obj1['id'] = str(obj.key.id())
            return obj1

        if isinstance(obj, query.Query):
            return list(obj)
        elif isinstance(obj, datetime.datetime):
            return 1000 * (time.mktime(obj.timetuple()) + (obj.microsecond))
        elif isinstance(obj, datetime.date):
            return 1000 * time.mktime(obj.timetuple())
        elif isinstance(obj, time.struct_time):
            return list(obj)
        elif isinstance(obj, ndb.Key):
            return obj.get()
        elif isinstance(obj, ndb.BlobKey):
            return str(obj)
        return json.JSONEncoder.default(self, obj)


def model_encode(input):
    """
    Encode an input Model object as JSON

    Args:
        input: A Model object or DB property.

    Returns:
        A JSON string based on the input object.

    Raises:
        TypeError: Typically occurs when an input object contains an unsupported type.
    """
    return ModelEncoder().encode(input)


class MLStripper(HTMLParser):

    def __init__(self):
        self.reset()
        self.fed = []

    def handle_data(self, d):
        self.fed.append(d)

    def get_data(self):
        return ''.join(self.fed)


def remove_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()
